package com.zerui.manager.openplan.domainservice;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zerui.cola.dto.Response;
import com.zerui.manager.openplan.OpenPlan;
import com.zerui.manager.openplan.OpenPlanImplement;
import com.zerui.manager.openplan.gateway.OpenPlanGateWay;
import com.zerui.manager.web.cmd.OpenPlanQryCmd;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @Author wh
 * @create_time 2023-08-23 15:28
 */
@Component
public class OpenPlanRepository {

	@Resource
	private OpenPlanGateWay openPlanGateWay;
	@Resource
	private OpenPlanTask openPlanTask;

    public OpenPlan selectById(Long id) {
        return openPlanGateWay.selectById(id);
    }

    @Transactional
    public Response disable(OpenPlan openPlan) {
        deleteOpenPlanImplement(openPlan.getId());
        openPlan.setAccept(false);
        openPlanGateWay.updateById(openPlan);
        return Response.buildSuccess();
    }

    private void deleteOpenPlanImplement(Long id) {
        openPlanGateWay.deleteImplementByPlanId(id);
    }

    @Transactional
    public Response enable(OpenPlan openPlan) {
        //根据配置生成 OpenPlanImplement
        List<OpenPlanImplement> implementList =  createOpenPlanImplement(openPlan);
        openPlanGateWay.addBatchImplements(implementList);
        openPlan.setAccept(true);
        openPlanGateWay.updateById(openPlan);

        List<OpenPlanImplement> newImplements =  openPlanGateWay.selectImplementById(openPlan.getId());

        //当天的计划添加到延迟队列
        newImplements.forEach(e-> openPlanTask.addTsk(e.getId(),e.getOperationTime().toInstant(ZoneOffset.of("+8")).toEpochMilli()));
        return Response.buildSuccess();
    }

    private List<OpenPlanImplement> createOpenPlanImplement(OpenPlan openPlan) {

        Map<String,List<LocalDateTime>> map = obtainTime(openPlan);
        List<OpenPlanImplement> implementList = new ArrayList<>();
        AtomicReference<Integer> operation = new AtomicReference<>(0);
        map.forEach((key,val)->{
            if("open".equals(key)){
                operation.set(1);
            }
	        val.forEach(e-> implementList.add(OpenPlanImplement.builder()
	                .openPlanId(openPlan.getId())
	                .operationTime(e)
	                .operation(operation.get())
	                .implement(false)
	                .createTime(LocalDateTime.now())
	                .build()));

        });

        return implementList;

    }

    private Map<String,List<LocalDateTime>> obtainTime(OpenPlan openPlan) {
        LocalDate firstDay = openPlan.getStartDate();
        LocalDate lastDay  = openPlan.getEndDate();
        LocalTime startTime = openPlan.getStartTime();
        LocalTime endTime = openPlan.getEndTime();
        LocalDate localDateTemporary = firstDay;
        List<LocalDate> localDateList = new ArrayList<>();
        if(!(!openPlan.getWeekend() && isWeekend(firstDay))){
            localDateList.add(firstDay);
        }
        while (localDateTemporary.isBefore(lastDay)) {
            LocalDate minus = localDateTemporary.minusDays(-1);
            if(!(!openPlan.getWeekend() && isWeekend(firstDay))){
                localDateList.add(minus);
            }
            localDateTemporary = minus;
        }
        List<LocalDateTime> openTimeList = new ArrayList<>();
        List<LocalDateTime> closeTimeList = new ArrayList<>();
        localDateList.forEach(e->{
            openTimeList.add(e.atTime(startTime));
            closeTimeList.add(e.atTime(endTime));
        });
        Map<String,List<LocalDateTime>> map = new HashMap<>();
        map.put("open",openTimeList);
        map.put("close",closeTimeList);
        return map;

    }

    private Boolean isWeekend(LocalDate localDate){
        DayOfWeek dayOfWeek = localDate.getDayOfWeek();
        return dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY;
    }

    public Page<OpenPlan> getPageList(OpenPlanQryCmd openPlanQryCmd) {
        return openPlanGateWay.getPageList(openPlanQryCmd);
    }

}
